package net.lab0.fractal.fractals.mandelbrot;


public class MandelbrotComputationThread
extends Thread
{
	private static int						threadNumber	= 0;
	private MultithreadedMandelbrotFractal	parent;
	private int								compH;
	private int								compW;
	private double							xStep;
	private double							yStep;
	private double							xCenter;
	private double							yCenter;
	private double							viewportWidth;
	private double							viewportHeight;
	private int								slice;
	private int								slices;
	private boolean							stop			= false;
	private boolean							go				= false;
	
	public MandelbrotComputationThread(MultithreadedMandelbrotFractal parent)
	{
		super("MandelbrotComputationThread-" + threadNumber);
		threadNumber++;
		this.parent = parent;
	}
	
	@Override
	public void run()
	{
		while (!stop)
		{
			if (go)
			{
				go = false;
				computationBlock();
				parent.notifyFinished(this);
			}
			else
			{
				synchronized (this)
				{
					try
					{
						System.out.println("wait " + Thread.currentThread().getName());
						wait();
					}
					catch (InterruptedException e)
					{
						e.printStackTrace();
					}
				}
			}
		}
	}
	
	protected void computationBlock()
	{
		long maxIteration = parent.getMaxIteration();
		for (int y = slice; y < compH; y += slices)
		{
			if (parent.restartTest())
			{
				break;
			}
			parent.pauseTest();
			
			parent.setProgress((float) y / (float) compH, this);
			
			for (int x = 0; x < compW; x++)
			{
				long iter = 0;
				double x0, x1, y0, y1;
				x0 = x1 = xCenter - viewportWidth / 2 + xStep * x;
				y0 = y1 = yCenter + viewportHeight / 2 - yStep * y;
				// cardiod + 1st bulb test, cf wiki
				double q = (x0 - 0.25) * (x0 - 0.25) + y0 * y0;
				boolean inside = (q * (q + (x0 - 0.25)) < y0 * y0 * 0.25) || (((x0 + 1) * (x0 + 1) + y0 * y0) < 0.0625);
				if (!inside)
				{
					while (x1 * x1 + y1 * y1 <= 4 && iter < maxIteration)
					{
						double tempX = x1 * x1 - y1 * y1 + x0;
						y1 = 2 * x1 * y1 + y0;
						x1 = tempX;
						iter++;
					}
				}
				else
				{
					iter = maxIteration;
				}
				parent.pixels[x][y] = iter;
			}
		}
	}
	
	public void setGo(boolean go)
	{
		if (go == true)
		{
			System.out.println("notify " + Thread.currentThread().getName());
			this.go = go;
			synchronized (this)
			{
				notifyAll();
			}
		}
	}
	
	public int getSlice()
	{
		return slice;
	}
	
	public void setSlice(int slice)
	{
		this.slice = slice;
	}
	
	public float getSlices()
	{
		return slices;
	}
	
	public void setSlices(int slices)
	{
		this.slices = slices;
	}
	
	public void setCompH(int compH)
	{
		this.compH = compH;
	}
	
	public void setCompW(int compW)
	{
		this.compW = compW;
	}
	
	public void setxStep(double xStep)
	{
		this.xStep = xStep;
	}
	
	public void setyStep(double yStep)
	{
		this.yStep = yStep;
	}
	
	public void setxCenter(double xCenter)
	{
		this.xCenter = xCenter;
	}
	
	public void setyCenter(double yCenter)
	{
		this.yCenter = yCenter;
	}
	
	public void setViewportWidth(double viewportWidth)
	{
		this.viewportWidth = viewportWidth;
	}
	
	public void setViewportHeight(double viewportHeight)
	{
		this.viewportHeight = viewportHeight;
	}
	
	public void setStop(boolean stop)
	{
		this.stop = stop;
	}
	
}
